#include <cassert>
#include "logger.h"
#include "../lfqueue/lfqueue.cpp"
#include "../lfqueue/lock_queue.cpp"

// TODO (me): replace asserts with exceptions

using std::string;
using std::ofstream;
using std::atomic;
using std::thread;
using std::this_thread::yield;
using std::endl;
using std::ios_base;

Logger Logger::instance_;

Logger::Logger(): active_(false) {
}

Logger::~Logger() {
	if (instance_.active_.load())
		Stop();
}

void Logger::LoggerThreadFunc() {
	string s;
	while (instance_.active_.load()) {
		while (instance_.message_queue_->Dequeue(&s))
			instance_.fout_ << s << endl; 
		yield();
	}

	while (instance_.message_queue_->Dequeue(&s))
		instance_.fout_ << s << endl; 

}

void Logger::Start(Priority min_priority, const string& log_file) {
	assert(!instance_.active_.load());
	instance_.min_priority_ = min_priority;
	instance_.fout_.open(log_file, ios_base::out);
	assert(instance_.fout_.is_open());
	
	instance_.message_queue_ = new LFQueue<string>();
	instance_.active_.store(true);
	instance_.pthread_ = new thread(&(Logger::LoggerThreadFunc));
}

void Logger::Stop() {
	assert(instance_.active_);

	instance_.active_.store(false);
	instance_.pthread_->join();
	delete instance_.message_queue_;
	instance_.fout_.close();
}

void Logger::Write(Priority priority, const string &message) {
	assert(instance_.active_.load());
	if (priority < instance_.min_priority_)
		return;

	instance_.message_queue_->Enqueue(message);
}

